# doc.rb
#   doc-generation rake tasks
#
# Created 2012-05-21 daveadams@gmail.com
# Last updated 2014-01-06 daveadams@gmail.com
#
# https://github.com/daveadams/sakai-info
#
# This software is public domain.
#

DOCSRCDIR = File.join(BASEDIR, 'doc-src')
DOCDIR = File.join(BASEDIR, 'doc')
GRAPHDIR = File.join(DOCDIR, 'graphs')
GRAPHVIZDIR = File.join(TMPDIR, 'doc', 'graphviz')

namespace :doc do
  task :create_doc_dir do
    if not Dir.exist? DOCDIR
      print "Creating directory for generated documentation... "; STDOUT.flush
      system "mkdir -p #{DOCDIR}"
      puts "OK"
    end
  end

  namespace :db do
    TableRelationshipsFile = File.join(DOCSRCDIR, "table-relationships.yml")

    task :ensure_graphviz_support do
      dot_path = `which dot 2>/dev/null`.chomp
      if dot_path.nil?
        STDERR.puts "ERROR: Graphviz 'dot' utility was not found in your PATH"
        exit 1
      else
        dot_version = `dot -V 2>&1`.chomp
        if dot_version !~ /Graphviz version/i
          STDERR.puts "ERROR: The 'dot' utility in your PATH does not appear to be Graphviz"
          exit 1
        end
      end
    end

    task :create_graphviz_dir do
      if not Dir.exist? GRAPHVIZDIR
        print "Creating temporary directory for graphviz files... "; STDOUT.flush
        system "mkdir -p #{GRAPHVIZDIR}"
        puts "OK"
      end
    end

    desc "Generate graphviz for relationship charts"
    task :graphviz => :create_graphviz_dir do
      def write_graphviz_file(table_group, tables, db, relationships)
        print "Creating graphviz for #{table_group} tables... "; STDOUT.flush
        File.open(File.join(GRAPHVIZDIR, "#{table_group}.gv"), "w") do |f|
          f.puts "# #{table_group}.gv"
          f.puts "#   autogenerated graphviz file for #{table_group} tables"
          f.puts "#"
          f.puts "# Generated at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"
          f.puts "#"
          f.puts
          f.puts "digraph #{table_group} {"
          f.puts "  graph ["
          f.puts "    rankdir = \"RL\""
          f.puts "  ];"
          f.puts
          f.puts "  node ["
          f.puts "    shape = plaintext"
          f.puts "    fontname = mono"
          f.puts "    fontsize = 11"
          f.puts "  ];"
          f.puts

          # write out table details
          tables.each do |table_name|
            t = relationships[table_name]
            next if t.nil?

            f.puts "  \"#{table_name}\" ["
            f.print "    label=<<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">"
            if t["description"]
              f.print "<tr><td><font face=\"Arial\">#{t["description"]}</font></td></tr>"
            end
            f.print "<tr><td><table cellspacing=\"0\"><tr>"
            f.print "<td bgcolor=\"gray80\" cellpadding=\"5\">"
            f.print table_name
            f.print "</td></tr>"
            if not t["pk"].nil?
              # be sure primary key is printed first if it exists
              f.print "<tr><td port=\"pk\">#{t["pk"]}</td></tr>"
            end
            # then print everything else
            other_columns = ((db.schema(table_name.to_sym).collect{|f|f[0].to_s}) - [t["pk"]])
            other_columns.each do |column|
              f.print "<tr><td port=\"#{column}\">#{column}</td></tr>"
            end
            f.print "</table></td></tr></table>>\n"
            f.puts "  ]"
            f.puts
          end

          # write out foreign-key links
          tables.each do |table_name|
            t = relationships[table_name]
            next if t.nil? or t["fk"].nil?
            t["fk"].each do |fk|
              # only if foreign table is in this table set
              if tables.include? fk["table"]
                f.puts "  #{table_name}:#{fk["field"]} -> #{fk["table"]}:pk;"
              end
            end
          end
          f.puts "}"
        end
        puts "OK"
      end

      db = db_connect
      relationships = YAML::load_file(TableRelationshipsFile)

      Tables.keys.each do |table_group|
        tables = []
        Tables[table_group].each do |table|
          if not relationships[table.to_s].nil?
            tables << table.to_s
          end
        end

        if tables.length > 0
          write_graphviz_file(table_group, tables, db, relationships)
        end
      end

      write_graphviz_file("all",
                          Tables.values.flatten.collect{|t|t.to_s},
                          db, relationships)
    end

    task :create_graphs_dir do
      if not Dir.exist? GRAPHDIR
        print "Creating directory for database graph files... "; STDOUT.flush
        system "mkdir -p #{GRAPHDIR}"
        puts "OK"
      end
    end

    desc "Create data relationship graphs"
    task :graphs => [ :ensure_graphviz_support, :graphviz, :create_graphs_dir ] do
      puts "Processing graphviz database files:"
      Dir[File.join(GRAPHVIZDIR, "*.gv")].each do |gv_file|
        print "  Processing #{File.basename(gv_file)}... ";STDOUT.flush
        system "dot -Tpng -o #{GRAPHDIR}/#{File.basename(gv_file, ".gv")}.png #{gv_file}"
        puts "OK"
      end
    end
  end
end
